Get all scaleway server info copy

工作流概述

这是一个包含24个节点的复杂工作流,主要用于自动化处理各种任务。

工作流源代码

下载
{
  "id": "olDVR3wuxbUsTvuW",
  "meta": {
    "instanceId": "598c730c3a95b29c8be35b1b34a362ffa595154754b692ab1bb4baa1db7b1f33",
    "templateCredsSetupCompleted": true
  },
  "name": "Get all scaleway server info copy",
  "tags": [],
  "nodes": [
    {
      "id": "9da28130-ed83-4129-b65c-82969fe3126d",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        -60
      ],
      "parameters": {
        "jsCode": "// Function to extract essential information from servers
function extractServers(serversArray) {
    let servers = [];

    if (!Array.isArray(serversArray)) {
        console.log(\"⚠️ Invalid data received:\", JSON.stringify(serversArray, null, 2));
        return servers; // Returns an empty array if the data is not valid
    }

    serversArray.forEach(server => {
        servers.push({
            name: server.name || \"Unknown\",
            tags: server.tags && server.tags.length > 0 ? server.tags.join(\", \") : \"No tags\",
            public_ip: getPublicIPs(server),
            type: server.commercial_type || server.offer_name || \"Unknown\", // Baremetal does not have commercial_type, but offer_name
            state: server.state || server.status || \"Unknown\", // Baremetal uses status instead of state
            zone: server.zone || \"Unknown\",
            user: getUser(server) // User management
        });
    });

    return servers;
}

// Function to extract the public IP (IPv4 prioritized, otherwise IPv6)
function getPublicIPs(server) {
    let ipv4 = null;
    let ipv6 = null;

    // Case for Compute instances (public_ips is an array)
    if (server.public_ips && Array.isArray(server.public_ips)) {
        server.public_ips.forEach(ip => {
            if (ip.family === \"inet\" && !ipv4) ipv4 = ip.address;
            if (ip.family === \"inet6\" && !ipv6) ipv6 = ip.address;
        });
    }

    // Some instances have public_ip as a single object
    if (server.public_ip && server.public_ip.address) {
        if (server.public_ip.family === \"inet\" && !ipv4) ipv4 = server.public_ip.address;
        if (server.public_ip.family === \"inet6\" && !ipv6) ipv6 = server.public_ip.address;
    }

    // Case for Baremetal servers (ips is an array)
    if (server.ips && Array.isArray(server.ips)) {
        server.ips.forEach(ip => {
            if (ip.version === \"IPv4\" && !ipv4) ipv4 = ip.address;
            if (ip.version === \"IPv6\" && !ipv6) ipv6 = ip.address;
        });
    }

    // Returns IPv4 if available, otherwise IPv6, otherwise \"No IP\"
    return ipv4 || ipv6 || \"No IP\";
}

// Function to retrieve the user
function getUser(server) {
    // For Compute instances, the \"user\" field sometimes exists
    if (server.user) return server.user;

    // For Baremetal servers, user info is often found in install.user
    if (server.install && server.install.user) return server.install.user;

    // Default value
    return \"root\";
}

// Retrieve all input items (from Loop Over Zone Instance)
let inputItems = $input.all();
let allServers = [];

// Iterate over each item and extract servers if they are contained in a \"servers\" property
inputItems.forEach(item => {
    if (item.json.servers && Array.isArray(item.json.servers)) {
        allServers = allServers.concat(extractServers(item.json.servers));
    } else {
        // If the item does not have a \"servers\" property, attempt to process the object itself as a server
        allServers = allServers.concat(extractServers([item.json]));
    }
});

// Return the final result as items (JSON object per server)
return allServers.map(server => ({ json: server }));
"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "12e10b9e-99ca-4ab8-b90d-be318ba2f9ff",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        880,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e6764348-1fa6-439e-9279-3b423c7c73af",
              "name": "search_by",
              "type": "string",
              "value": "={{ $json.body.search_by }}"
            },
            {
              "id": "5535e47b-c187-47eb-80af-bccb3972f4a5",
              "name": "search",
              "type": "string",
              "value": "={{ $json.body.search }}"
            },
            {
              "id": "b69ff3d1-885e-4145-a277-074b8e517aaf",
              "name": "Scaleway-X-Auth-Token",
              "type": "string",
              "value": "<Your personal Scaleway X Auth Token>"
            },
            {
              "id": "65ee376e-093f-4a8b-abe8-5d9173d26427",
              "name": "ZONE_INSTANCE",
              "type": "array",
              "value": "[\"fr-par-1\", \"fr-par-2\", \"fr-par-3\", \"nl-ams-1\", \"nl-ams-2\", \"nl-ams-3\", \"pl-waw-1\", \"pl-waw-2\", \"pl-waw-3\"]"
            },
            {
              "id": "9a9fff0b-f812-4bb1-800e-2376b39381ed",
              "name": "ZONE_BAREMETAL",
              "type": "string",
              "value": "[\"fr-par-1\", \"fr-par-2\", \"nl-ams-1\", \"nl-ams-2\", \"pl-waw-2\", \"pl-waw-3\"]"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "20398633-d856-4700-98a9-1f722f3d2a8f",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        2260,
        -80
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "7ee5d5ae-3a88-4bef-820d-979c26499cbd",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Edit Fields').first().json.search_by }}",
                    "rightValue": "tags"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "eb879619-5b97-4402-b3de-3f98e0a7d0d3",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Edit Fields').first().json.search_by }}",
                    "rightValue": "name"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "2d0b6397-e46d-484a-84a0-7af8d7345dea",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Edit Fields').first().json.search_by }}",
                    "rightValue": "public_ip"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "0ee8fb2d-cf38-4994-a49a-88c7482b46ab",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Edit Fields').first().json.search_by }}",
                    "rightValue": "zone"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "04a298b2-2a22-433a-a8db-3902dcff0425",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Edit Fields').first().json.search_by }}",
                    "rightValue": "null"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "ignoreCase": false,
          "fallbackOutput": "extra"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "f480f721-d2b3-49a4-9211-266af3e8fd42",
      "name": "Code search Tags",
      "type": "n8n-nodes-base.code",
      "position": [
        2680,
        -500
      ],
      "parameters": {
        "jsCode": "// Retrieve all input items
let servers = $input.all();

// Filter only servers with the tag \"STAGING\"
let filteredServers = servers.filter(server =>
    server.json.tags && server.json.tags.includes($('Edit Fields').first().json.search)
);

// Return only servers that have \"search\" in the tags
return filteredServers;
"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "44ee26b2-1320-44a6-a705-ff102e789a9c",
      "name": "Code search Name",
      "type": "n8n-nodes-base.code",
      "position": [
        2680,
        -340
      ],
      "parameters": {
        "jsCode": "// Retrieve all input items
let servers = $input.all();

// Filter only servers with the tag \"STAGING\"
let filteredServers = servers.filter(server =>
    server.json.name && server.json.name.includes($('Edit Fields').first().json.search)
);

// Return only servers that have \"search\" in the name
return filteredServers;
"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "b8e5f1b5-09a0-42f8-a5d6-a10989cb9f81",
      "name": "Code search public_ip",
      "type": "n8n-nodes-base.code",
      "position": [
        2680,
        -180
      ],
      "parameters": {
        "jsCode": "// Retrieve all input items
let servers = $input.all();

// Filter only servers with the tag \"STAGING\"
let filteredServers = servers.filter(server =>
    server.json.public_ip && server.json.public_ip.includes($('Edit Fields').first().json.search)
);

// Return only servers that have \"search\" in the public_ip
return filteredServers;
"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "1029d9bc-8d42-4038-9dfe-f8957e9115b6",
      "name": "Code search zone",
      "type": "n8n-nodes-base.code",
      "position": [
        2680,
        -20
      ],
      "parameters": {
        "jsCode": "// Retrieve all input items
let servers = $input.all();

// Filter only servers with the tag \"STAGING\"
let filteredServers = servers.filter(server =>
    server.json.public_ip && server.json.public_ip.includes($('Edit Fields').first().json.search)
);

// Return only servers that have \"search\" in the public_ip
return filteredServers;
"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "3dae20ba-07b2-4948-a58c-8b803f672dcb",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        660,
        0
      ],
      "webhookId": "a6767312-3a4c-4819-b4fe-a03c9e0ade5c",
      "parameters": {
        "path": "a6767312-3a4c-4819-b4fe-a03c9e0ade5c",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode",
        "authentication": "basicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "id": "YzpBkNOC0UnKboCn",
          "name": "Endpoint Get server scalway info"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "65f62d8f-aead-47cb-a9df-105054d8b666",
      "name": "Respond Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2680,
        300
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={
  \"error\": \"no search by {{ $('Edit Fields').item.json.search_by }} available. You can search by : tags, name, public_ip, zone\"
}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "9d8db89d-c318-4078-9a3d-8bc10022d059",
      "name": "Respond to Webhook1",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2900,
        -340
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "3009a593-8a23-448c-b8fd-58c6fc4b77b3",
      "name": "Respond to Webhook2",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2900,
        -180
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "27e1f543-c57c-4772-944b-d2207526dd9d",
      "name": "Respond to Webhook3",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2900,
        -20
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "90e51c36-9888-4942-ad13-28fa90235d13",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2900,
        -500
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "92ad3cf2-c3b3-4c42-9d1b-7d55f3e5ad56",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        -1240
      ],
      "parameters": {
        "color": 4,
        "width": 1000,
        "height": 1080,
        "content": "# Technical Documentation

## Description

This n8n workflow retrieves information about Scaleway servers—both instances and baremetal—from dynamically defined zones. It collects server details from the Scaleway API, aggregates them into a single dataset, and allows filtering of the results based on user-defined criteria (such as name, tags, public IP address, or zone) before returning the data via a webhook.

## Operation

### 1. Workflow Trigger

- **Webhook Activation:**
  The workflow is triggered by a Webhook node that listens for an HTTP POST request. This request uses basic authentication (basicAuth) and includes the search parameters:
  - `search_by`: The filter type (e.g., \"tags\", \"name\", \"public_ip\", or \"zone\").
  - `search`: The keyword to filter the server data.

### 2. Retrieving Server Information

- **HTTP Requests to Scaleway API:**
  The workflow makes HTTP GET requests to two main Scaleway API endpoints:
  - **Instances Endpoint:** Retrieves server instances from zones specified under the `ZONE_INSTANCE` variable.
  - **Baremetal Endpoint:** Retrieves baremetal server information from zones defined in the `ZONE_BAREMETAL` variable.
  - **Headers and Authentication:**
    Each request sends the `X-Auth-Token` header along with a `Content-Type: application/json` header and expects a JSON response from the API.

### 3. Data Processing

- **Zone Splitting and Iteration:**
  - A `Split Out ZONE_INSTANCE` node divides the list of predefined zones so each zone is processed separately.
  - The `Loop Over Zone Instance` node iterates over the zones. An `If ZONE_BAREMETAL in ZONE_INSTANCE` node checks whether the current zone is configured for baremetal servers; if so, it directs the flow to the corresponding baremetal API request, otherwise to the instance request.
  - **Aggregating and Structuring Data:**
    The `Code` node aggregates all responses from each zone. It:
    - Iterates over the incoming items.
    - Uses helper functions (`extractServers`, `getPublicIPs`, `getUser`) to extract and normalize key information (name, tags, public IP, server type, state, zone, user).
    - Consolidates the structured server information into a unified array for further processing.

### 4. Dynamic Filtering

- **Defining Search Criteria:**
  A `Set` node captures the incoming search parameters (`search_by` and `search`) along with configuration details, such as the Scaleway authentication token and the lists of applicable zones.
  - **Routing Based on Filter Type:**
    The `Switch` node analyzes the value of `search_by` and routes the aggregated server data to one of four dedicated `Code` nodes that filter the data according to:
    - `tags`
    - `name`
    - `public_ip`
    - `zone`
  - **Error Handling:**
    If the `search_by` value does not match any of the valid filters, an error response is generated via a dedicated node that returns a JSON error message listing the available filter options.

### 5. Response via Webhook

- **Returning the Filtered Data:**
  The filtered server data is sent back to the requester via one of several `Respond to Webhook` nodes assigned to handle the output from each filter type.
  - **Error Response:**
    In cases where no valid search criteria are provided, the workflow sends an error JSON response indicating that the valid filters are: `tags`, `name`, `public_ip`, and `zone`.

## Example Usage

To use the workflow from an application or another workflow, send a POST request to the webhook endpoint with a JSON payload similar to this:

```json
{
  \"search_by\": \"tags\",
  \"search\": \"Apiv1\"
}
```

If executed successfully, the workflow will return a JSON array with server objects. Each object includes properties such as:
- `name`
- `tags`
- `public_ip`
- `type`
- `state`
- `zone`
- `user`"
      },
      "typeVersion": 1
    },
    {
      "id": "0fc94a1e-2cb3-47d7-a198-a053b2bed8e4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1060,
        520
      ],
      "parameters": {
        "width": 960,
        "height": 660,
        "content": "# Usage in an External App or Another Workflow

To integrate this part of the workflow into your application or another workflow:

1. **Send a POST Request:**
   Use the Get Scalway Machines node’s endpoint (displayed under the node) to send a POST request containing the search criteria. For example:

   ```json
   {
     \"search_by\": \"tags\",
     \"search\": \"Apiv1\"
   }
   ```

2. **Process the Results:**
   The Loop Over Items node will iterate over each response item, allowing you to handle multiple servers or records in one run.

3. **Receive the Filtered Data:**
   The returned data (each item representing a server) can then be processed further in your application or workflow, giving you a quick, automated way to retrieve and filter Scaleway server information."
      },
      "typeVersion": 1
    },
    {
      "id": "d54772b2-40e7-43ff-9c4c-d4bbf176c3c2",
      "name": "Get Scalway Machines",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1400,
        1020
      ],
      "parameters": {
        "url": "https://sup-n8n.unipile.com/webhook/209dd6cb-76cf-4841-8c79-cea45a742b39",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "search_by",
              "value": "Available filters (name, tags, public_ip, zone) or null if you don't want to apply a filter"
            },
            {
              "name": "search",
              "value": "Your search keyword"
            }
          ]
        },
        "genericAuthType": "httpBasicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "id": "YzpBkNOC0UnKboCn",
          "name": "Endpoint Get server scalway info"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "710b2503-ccb9-42d2-877a-034082a6fef8",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1600,
        1020
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "387d2a3d-8f2c-47be-a4c6-73ac110b03d0",
      "name": "Respond to Webhook4",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2680,
        140
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "09f05bba-5fe3-4e3f-b5e6-b6f75eb9400d",
      "name": "Get scw instance by zone",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1560,
        80
      ],
      "parameters": {
        "url": "=https://api.scaleway.com/instance/v1/zones/{{ $('Split Out ZONE_INSTANCE').item.json.ZONE_INSTANCE }}/servers",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Auth-Token",
              "value": "={{ $('Edit Fields').item.json['Scalway-X-Auth-Token'] }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "541d8cd6-f7db-49a1-b527-235813b82737",
      "name": "Loop Over Zone Instance",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1360,
        0
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "be293c2d-bd39-46f5-8c09-766cc145f8b7",
      "name": "Get scw baremetal by zone",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2000,
        80
      ],
      "parameters": {
        "url": "=https://api.scaleway.com/baremetal/v1/zones/{{ $('Split Out ZONE_INSTANCE').item.json.ZONE_INSTANCE }}/servers",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Auth-Token",
              "value": "={{ $('Edit Fields').item.json['Scalway-X-Auth-Token'] }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b12396b5-8fd6-4b06-8c41-0a14d2382937",
      "name": "Split Out ZONE_INSTANCE",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1100,
        0
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "ZONE_INSTANCE"
      },
      "typeVersion": 1
    },
    {
      "id": "b96d5ee0-db41-4ea8-a23f-2db3cea63a3c",
      "name": "If ZONE_BAREMETAL in ZONE_INSTANCE",
      "type": "n8n-nodes-base.if",
      "position": [
        1780,
        80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "874626f1-ecf5-42c4-86fe-01a9c68cbb1a",
              "operator": {
                "type": "array",
                "operation": "contains",
                "rightType": "any"
              },
              "leftValue": "={{ $('Edit Fields').item.json.ZONE_BAREMETAL }}",
              "rightValue": "={{ $('Loop Over Zone Instance').item.json.ZONE_INSTANCE }}"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "30234c35-1788-4857-bc58-c1a581be318f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -20,
        -140
      ],
      "parameters": {
        "color": 3,
        "width": 580,
        "height": 380,
        "content": "# Replace the Scaleway-X-Auth-Token Field

To ensure the workflow functions correctly, you must:

1. Open the Edit Fields node in your workflow.
2. Locate the Scaleway-X-Auth-Token field and enter your personal Scaleway token (replacing the default value).
3. If you do not have a token yet:
   - Log in to your Scaleway console.
   - Create a new API Token by following the [Scaleway documentation](https://www.scaleway.com/en/developers/api/).
   - Copy the generated token and paste it into the Scaleway-X-Auth-Token field."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "K3TJbThVR2T5RU8o",
    "executionOrder": "v1"
  },
  "versionId": "b38207e8-da63-462c-ac51-925d029d5a1f",
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Code search Tags",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code search Name",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code search public_ip",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code search zone",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook4",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Split Out ZONE_INSTANCE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code search Name": {
      "main": [
        [
          {
            "node": "Respond to Webhook1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code search Tags": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code search zone": {
      "main": [
        [
          {
            "node": "Respond to Webhook3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Scalway Machines": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code search public_ip": {
      "main": [
        [
          {
            "node": "Respond to Webhook2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Zone Instance": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get scw instance by zone",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out ZONE_INSTANCE": {
      "main": [
        [
          {
            "node": "Loop Over Zone Instance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get scw instance by zone": {
      "main": [
        [
          {
            "node": "If ZONE_BAREMETAL in ZONE_INSTANCE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get scw baremetal by zone": {
      "main": [
        [
          {
            "node": "Loop Over Zone Instance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If ZONE_BAREMETAL in ZONE_INSTANCE": {
      "main": [
        [
          {
            "node": "Get scw baremetal by zone",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over Zone Instance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

功能特点

  • 自动检测新邮件
  • AI智能内容分析
  • 自定义分类规则
  • 批量处理能力
  • 详细的处理日志

技术分析

节点类型及作用

  • Code
  • Set
  • Switch
  • Webhook
  • Respondtowebhook

复杂度评估

配置难度:
★★★★☆
维护难度:
★★☆☆☆
扩展性:
★★★★☆

实施指南

前置条件

  • 有效的Gmail账户
  • n8n平台访问权限
  • Google API凭证
  • AI分类服务订阅

配置步骤

  1. 在n8n中导入工作流JSON文件
  2. 配置Gmail节点的认证信息
  3. 设置AI分类器的API密钥
  4. 自定义分类规则和标签映射
  5. 测试工作流执行
  6. 配置定时触发器(可选)

关键参数

参数名称 默认值 说明
maxEmails 50 单次处理的最大邮件数量
confidenceThreshold 0.8 分类置信度阈值
autoLabel true 是否自动添加标签

最佳实践

优化建议

  • 定期更新AI分类模型以提高准确性
  • 根据邮件量调整处理批次大小
  • 设置合理的分类置信度阈值
  • 定期清理过期的分类规则

安全注意事项

  • 妥善保管API密钥和认证信息
  • 限制工作流的访问权限
  • 定期审查处理日志
  • 启用双因素认证保护Gmail账户

性能优化

  • 使用增量处理减少重复工作
  • 缓存频繁访问的数据
  • 并行处理多个邮件分类任务
  • 监控系统资源使用情况

故障排除

常见问题

邮件未被正确分类

检查AI分类器的置信度阈值设置,适当降低阈值或更新训练数据。

Gmail认证失败

确认Google API凭证有效且具有正确的权限范围,重新进行OAuth授权。

调试技巧

  • 启用详细日志记录查看每个步骤的执行情况
  • 使用测试邮件验证分类逻辑
  • 检查网络连接和API服务状态
  • 逐步执行工作流定位问题节点

错误处理

工作流包含以下错误处理机制:

  • 网络超时自动重试(最多3次)
  • API错误记录和告警
  • 处理失败邮件的隔离机制
  • 异常情况下的回滚操作